46: 4EBA 0BAE 1000BF6 JSR FlushVol If a volume is available, flush it.
4A: 3C1F '<.' POP D6 Pop off error code.
4C: 206D FEC8 -$138 lab_3 MOVEA.L glob49(A5),A0 Now do the same thing with the right list box.
50: 2850 '(P' MOVEA.L (A0),A4
52: 4A6C 0058 'Jl.X' TST 88(A4)
56: 670E 1000066 BEQ.S lab_4
58: 4267 'Bg' CLR -(A7)
5A: 42A7 'B.' CLR.L -(A7)
5C: 3F2C 0058 '?,.X' PUSH 88(A4)
60: 4EBA 0B94 1000BF6 JSR FlushVol
64: 3C1F '<.' POP D6
Lets take a quick look and FlushVol and we can see a couple of things. Fist of all, we can quickly see what the parameters are: Parm1 is a pointer to the Volume Name, Parm2 is the Volume Ref Number. Looking back at MainEven, we see that the PEA 88(A4) is referring to the Volume Reference Number. FlushVol "writes the contents of the associated volume buffer and descriptive informatin about the volume (if they've changed since the last time FlushVol was called)." [IM II pg 89]. The returned result of this procedure is the OSErr.
72: A991 '..' _ModalDialog ; (filterProc:ProcPtr; VAR itemHit:INTEGER)
ModalDialog is the all-purpose dialog handler. It will monitor events and wait for an event involving an active dialog item. Upon returning, the dialog item number is returned in ModalDialog's 2nd parameter - in this case, vab_1. Once the trap returns, the program has to figure out what to do now that an item has been activated. Below, is a simple jump table that repeatedly subtracts integers from vab_1 until it is zero, at which point the program knows that it has the proper dialog item. It then branches to the appropriate routine.
ModalDialog also takes a parameter that specifies a special procedure that it can call whenever an event occurs. What that means, is that the line PEA MYFILTER is telling ModalDialog to execute the procedure MYFILTER anytime an event occurs. We can take a look at MYFILTER to see what it is doing (although in cracking, we probably don't care). Right now I will guess that MYFILTER is taking care of things like allowing multiple selections in the list boxes,. displaying the font string, and displaying the size of the selection.
74: 302E FFFA 200FFFA MOVE vab_1(A6),D0
78: 5540 'U@' SUBQ #2,D0 Copy button.
7A: 6736 10000B2 BEQ.S lab_7
7C: 5340 'S@' SUBQ #1,D0 Remove Button.
7E: 672C 10000AC BEQ.S lab_6
80: 5340 'S@' SUBQ #1,D0 Help Button.
82: 6734 10000B8 BEQ.S lab_8
84: 5340 'S@' SUBQ #1,D0 Quit Button.
86: 6720 10000A8 BEQ.S lab_5
88: 5340 'S@' SUBQ #1,D0 Left Open/Close Button.
8A: 673C 10000C8 BEQ.S lab_10
8C: 5340 'S@' SUBQ #1,D0 Right Open/Close Button.
8E: 6742 10000D2 BEQ.S lab_11
90: 5340 'S@' SUBQ #1,D0 Font Radio Button.
92: 672A 10000BE BEQ.S lab_9
94: 5340 'S@' SUBQ #1,D0 DA Radio Button.
96: 6726 10000BE BEQ.S lab_9
98: 5340 'S@' SUBQ #1,D0 Left List Box.
9A: 6740 10000DC BEQ.S lab_12
9C: 5340 'S@' SUBQ #1,D0 Right List Box.
9E: 674A 10000EA BEQ.S lab_13
A0: 0440 0028 '.@.(' SUBI #40,D0 We will have to check MyFilter to see what this is doing.
A4: 6752 10000F8 BEQ.S lab_14
A6: 6058 1000100 BRA.S lab_15
A8: 7E01 '~.' lab_5 MOVEQ #1,D7 User hit Quit, so disable the loop and jump to the loop end.
C2: 4EAD 022A 20064F2 JSR SELCLICK(A5) and change to either Fonts or DAs.
C6: 6038 1000100 BRA.S lab_15
C8: 2F2D FEC4 -$13C lab_10 PUSH.L glob48(A5)
CC: 4EAD 0242 2006B50 JSR DOCFILE(A5) Left Open (or close) Button.
D0: 602E 1000100 BRA.S lab_15
D2: 2F2D FEC8 -$138 lab_11 PUSH.L glob49(A5)
D6: 4EAD 0242 2006B50 JSR DOCFILE(A5) Right Open (or close) Button.
DA: 6024 1000100 BRA.S lab_15
DC: 2F2D FEC4 -$13C lab_12 PUSH.L glob48(A5) Remember this guy? Refers to the left box.
E0: 2F2D FFE8 -$18 PUSH.L glob62(A5)
E4: 4EAD 0202 2005CB8 JSR CONTENTC(A5) Handle a list box click.
E8: 6016 1000100 BRA.S lab_15
EA: 2F2D FEC8 -$138 lab_13 PUSH.L glob49(A5) Refers to the right list box.
EE: 2F2D FFE8 -$18 PUSH.L glob62(A5)
F2: 4EAD 0202 2005CB8 JSR CONTENTC(A5) List box handler.
F6: 6008 1000100 BRA.S lab_15
F8: 3F2D FEDC -$124 lab_14 PUSH glob55(A5)
FC: 4EAD 0232 2006A6A JSR HANDLEIN(A5)
100: 1007 '..' lab_15 MOVE.B D7,D0 Here is the end of the main loop. This checks to see if the loop should terminate. If not, branch back to the beginning of the loop.
102: 6700 FF06 100000A BEQ lab_1
106: 4CDF 10C0 'L...' MOVEM.L (A7)+,D6-D7/A4 At this point, either an error occurred or the user has hit the Quit button.
10A: 4E5E 'N^' UNLK A6
10C: 4E75 'Nu' RTS
10E: CD41 494E 4556 454E data1 DNAME MAINEVEN,0,0
HANDLEBU Procedure
5DCA: QUAL HANDLEBU ; b# =501 s#2 =proc214
vid_1 VEQU -272
vid_2 VEQU -256
5DCA: VEND
A quick observation here. After scanning the first few lines, you can notice some hereto unknown things. Look at the references to glob50. At this point, we know that globs 48 and 49 have been set up to refer (we don't know exactly how) to the two list boxes in the main dialog. A quick look down a ways reveals that D7 is used to pass an integer to our DrawString procedure (proc5). If we assume that D7 is the ID # of the STR# resource (since this is the parameter that proc5 requires), then that MOVEQ 1,D7 (line 5) must refer to STR# 1 which reads "Copy". The next two strings in the resource are "<<Copy<<" and ">>Copy>>" which are exactly the three strings that the copy button on the dialog can contain. So we might assume right now that glob50 refers to one of the list boxes, and can be used to determine whether the user has selected an item(s) in the list box. Based upon this information, the procedure will fill in the copy button with the proper string.
;-refs - 1/MAINEVEN
5DCA: 4E56 FEEE 'NV..' HANDLEBU LINK A6,#-$112
5DCE: 48E7 0308 'H...' MOVEM.L D6-D7/A4,-(A7)
5DD2: 4AAD FECC -$134 TST.L glob50(A5) Check the list box (it seems)
5DD6: 660C 2005DE4 BNE.S lid_1 Look at what this branch is skipping.
5DD8: 7E01 '~.' MOVEQ #1,D7 The string is "Copy".
5DDA: 3F3C 0003 '?<..' PUSH #3 DIMITEM needs the item number to dim as a parm. Item 3 is the Remove button.
5DDE: 4EBA A308 20000E8 JSR DIMITEM Take a quick look at DIMITEM and you will see that it takes an item number as a parameter, pushes the parameter, then pushes the number -1 (255 if we are talking about signed numbers) and calls HILITEIT which uses the 2nd parameter to either set or dim the desired button.
5DE2: 607A 2005E5E BRA.S lid_8 The Remove button is dimmed anytime there is no selection in one of the list boxes. How did this procedure know there was no selection? It checked to see if glob50 was blank (or possible a NIL pointer) and if so, there is no selection.
5DE4: 202D FECC -$134 lid_1 MOVE.L glob50(A5),D0 Here is the real key. glob50 is being compared to glob48. We know glob48 has something to do with the left list box, and look what happens if they are the same...D7 gets 3 which means string">>Copy>>" - the user has made a selection in the left list box.
5DE8: B0AD FEC4 -$13C CMP.L glob48(A5),D0
5DEC: 6604 2005DF2 BNE.S lid_2
5DEE: 7E03 '~.' MOVEQ #3,D7
5DF0: 6002 2005DF4 BRA.S lid_3
5DF2: 7E02 '~.' lid_2 MOVEQ #2,D7 Otherwise the user has made a selection in the right list box. A quick note: glob50 was not compared to glob49, but it was compared to glob48. We can deduce from this that glob50 had to contain either glob48 or glob49. What this means is that glob50 seems to indicate that something has been selected in one of the list boxes or is empty if there is no selection.
5DF4: 206D FECC -$134 lid_3 MOVEA.L glob50(A5),A0 This is a mess. We know that glob50 is a handle to a host of information about one of the list boxes, but we didn't bother to figure which bytes mean what. The best thing to do here is to analyze all the branches in the mess, see where they go, and look at what happens as a result of each branch. So...
5DF8: 2050 ' P' MOVEA.L (A0),A0
5DFA: 2068 0004 ' h..' MOVEA.L 4(A0),A0
5DFE: 2050 ' P' MOVEA.L (A0),A0
5E00: 3C28 0058 '<(.X' MOVE 88(A0),D6 Look familiar? Let's guess that this is a vRefNum for the list box containing the selection.
5E04: 206D FECC -$134 MOVEA.L glob50(A5),A0
5E08: 2050 ' P' MOVEA.L (A0),A0
5E0A: 2068 0004 ' h..' MOVEA.L 4(A0),A0
5E0E: 2050 ' P' MOVEA.L (A0),A0
5E10: 4A68 0056 'Jh.V' TST 86(A0)
5E14: 6C02 2005E18 BGE.S lid_4 OK, here is a branch. If it executes, D6 has something (which we guessed to be a vRefNum) in it which gets passed on to lid_4.
5E16: 4246 'BF' CLR D6 Otherewise, D6 is zeroed (no volume available).
5E18: 4A46 'JF' lid_4 TST D6
5E1A: 57C0 'W.' SEQ D0 D0=FF hex if there is no volume.
5E1C: 4A00 'J.' TST.B D0
5E1E: 6616 2005E36 BNE.S lid_5 This branch executes if D6 was zero and will cause 1 to moved into D7 - "Copy".
5E20: 2F00 '/.' PUSH.L D0 Save D0 on the stack (not a parameter)
5E22: 4267 'Bg' CLR -(A7) Create space on the stack for the return value.
5E24: 3F06 '?.' PUSH D6 Aha! We were right. proc6 needs a vRefNum and here is good old D6 being pushed as a parm. D6 is indeed the vRefNum.
5E26: 4EAD 0032 10004CA JSR proc6(A5) Takes a vRefNum as a parm, then does a GetVolInfo, and checks the iovAttributes to see if the disk is locked. Returns a 1 if locked, 0 if unlocked.
5E2A: 121F '..' POP.B D1 Pop off the locked status.
5E2C: 201F ' .' POP.L D0 Pop off the original D0.
5E2E: 8001 '..' OR.B D1,D0 Or them so that, in effect, the AND instruction below will be ANDing both D0 and D1 with 1.
5E30: 0240 0001 '.@..' ANDI #1,D0 Check to see if one of the two contains a non-zero value,
5E34: 6702 2005E38 BEQ.S lid_6 and if so, do not put a 1 in D7 (the string is not "Copy").
5E36: 7E01 '~.' lid_5 MOVEQ #1,D7 String is "Copy" (meaning that DA Mover will not allow the Copy to proceed) and from the above code, we might guess that this is a result of the destination volume being locked so copying is impossible.
5E38: 4267 'Bg' lid_6 CLR -(A7)
5E3A: 206D FECC -$134 MOVEA.L glob50(A5),A0 And here is basically the same as above except that the other list box's volume is being checked
5E3E: 2050 ' P' MOVEA.L (A0),A0
5E40: 3F28 0058 '?(.X' PUSH 88(A0) Push the vRefNum of the volume from which the selection has been made.
5E4C: 3F3C 0003 '?<..' PUSH #3 If the volume is locked, we cannot remove anything so dim the Remove Button.
5E50: 4EBA A296 20000E8 JSR DIMITEM
5E54: 6008 2005E5E BRA.S lid_8
5E56: 3F3C 0003 '?<..' lid_7 PUSH #3 Else activate the Remove Button (volume is not locked).
5E5A: 4EBA A2AE 200010A JSR UNDIMITE
OK, let's re-cap for a minute. If you look back at MakeAWin, you will note that glob48 and glob49 are set up to refer to information about the left and right list boxes respectively. We also know that these globs contain information about the volume (and possibly the file) that is being displayed in the list boxes - since 88 bytes off the start of the pointer is the volume reference number. The above code can be broken into two pieces: from line 5DF4, to lid_5 and from lid_6 to one line past lid_7. The first piece is messy, but the end result is that the destination volume is tested to see if it is locked, and if so, the copy button text is set to "Copy". Therefore we can now assume that all that messy stuff beforehand was in essence setting a pointer to the destination list box information. Remember from MakeAWin there was a strange section of code that seemed to link the two globs to each other? Well, now we see that glob50 is set to one of these two (the one that contains a selection) but glob50 must also be able to access the other list box's volume to see if it is locked (or to see if copying to it is possible). The second section checks to see if the volume containing the selection is locked, and if so, Removing is not possible.
5E5E: BE6D FFF4 -$C lid_8 CMP.W glob65(A5),D7 Once again, we don't know what this glob means, but we can see what gets skipped if the branch executes. Once we know what gets skipped, we have a decent idea what the global means. Keep in mind that the global is being compared to D7 - the string resource ID #.
5E62: 6700 0082 2005EE6 BEQ lid_13 So if glob65 contains the ID # in D7, skip to the end of the procedure.
5E86: 4EAD 002A 100048C JSR proc5(A5) Once again, the DrawString procedure. D7 is the string # and vid_2 returns a pointer to the string.
5E8A: 2F2D FFF6 -$A PUSH.L glob66(A5) Look at the trap below. glob66 HAS to be a CtlHdl (Handle to a control object on a dialog),
5E8E: 486E FF00 200FF00 PEA vid_2(A6) and vid_2 we already know has the string whose ID # is in D7. Since D7's string is "Copy", ">>Copy>>", or "<<Copy<<", we can assume that the control in question is the Copy Button.
5E94: 3B47 FFF4 -$C MOVE D7,glob65(A5) Here is a clue! glob65 gets set to the string ID# - now this makes sense. Back up a few lines, glob65 was compared to D7 and if they were equal, all this stuff gets skipped. Now glob65 gets set to D7. It looks like the program is checking to see whether the Copy Button already has the correct string in it. If not, the above code changes it and updates glob65 to the new string ID# so that next time through the event loop, glob65 has the current ID # of the Copy Button's text.
5E98: 7001 'p.' MOVEQ #1,D0
5E9A: B047 '.G' CMP.W D7,D0 Remember: if D7 is 1, the string is "Copy", and no copying is allowed - either because nothing is selected, or because the destination volume is locked.
5E9C: 660A 2005EA8 BNE.S lid_9 If copying is to be allowed, then branch.
5E9E: 3F3C 0002 '?<..' PUSH #2 Refers to the Copy Button:
5EA2: 4EBA A266 200010A JSR UNDIMITE and - wait a second. Notice that this is backward! It is dimming the copy button if copying is allowed! I'm not sure why it does this, but look down a few lines...
5EA6: 6008 2005EB0 BRA.S lid_10
5EA8: 3F3C 0002 '?<..' lid_9 PUSH #2
5EAC: 4EBA A23A 20000E8 JSR DIMITEM
5EB0: 2F0C '/.' lid_10 PUSH.L A4
5EB2: A879 '.y' _SetClip ; (rgn:RgnHandle)
5EB4: 2F0C '/.' PUSH.L A4
5EB6: A8D9 '..' _DisposRgn ; (rgn:RgnHandle)
5EB8: 7001 'p.' MOVEQ #1,D0 Here we go. Now, if D7 is 1, dim the copy button, otherwise enable it.
5EBA: B047 '.G' CMP.W D7,D0
5EBC: 660A 2005EC8 BNE.S lid_11
5EBE: 3F3C 0002 '?<..' PUSH #2
5EC2: 4EBA A224 20000E8 JSR DIMITEM
5EC6: 6008 2005ED0 BRA.S lid_12
5EC8: 3F3C 0002 '?<..' lid_11 PUSH #2
5ECC: 4EBA A23C 200010A JSR UNDIMITE
5ED0: 206D FFF6 -$A lid_12 MOVEA.L glob66(A5),A0 We already saw (from the SetCTitle trap above) that glob66 is a handle to the Copy button.
5ED4: 2050 ' P' MOVEA.L (A0),A0 Convert the handle to a pointer.
5ED6: 43EE FEF0 200FEF0 LEA vid_1(A6),A1
5EDA: 5088 'P.' ADDQ.L #8,A0 Well, according to IM, adding 8 bytes to a pointer to a control record makes the pointer point to the a window that the control is in.
5EDC: 22D8 '".' MOVE.L (A0)+,(A1)+ So, move the WindowPtr to vid_1.
5EDE: 22D8 '".' MOVE.L (A0)+,(A1)+ and now move the Rect (next parameter in a control record) into vid_1.
5EE0: 486E FEF0 200FEF0 PEA vid_1(A6)
5EE4: A92A '.*' _ValidRect ; (goodRect:Rect) This trap tells the Window Manager not to update the region Rect.
5EE6: 4CDF 10C0 'L...' lid_13 MOVEM.L (A7)+,D6-D7/A4 And, now we are finished.
5EEA: 4E5E 'N^' UNLK A6
5EEC: 4E75 'Nu' RTS
I am not sure exactly what is going on there when it sets the button to the opposite that it is supposed to be, then sets it properly. I might hazard a guess that this technique somehow gurrantees that the region will get redrawn properly, but I really don't know - nor do I really care, for that matter. It is pretty clear what this procedure does - it updates the text and active status of the various buttons on the main dialog. Once this is done, MainEven can let the user make a selection, act upon the selection, and then the whole thing starts over.
Well, that wraps up the intensive assembly listing. Font/DA Mover has many more procedures, but the idea here was to look at an assembly listing and apply the stuff at the beginning of the tutorial to a real life situation and see if you can guess what is going on. Next I will discuss the use of TMON, and finally we will look at cracking a real application: Sorcerer. (I am choosing this because it is easy, and I recently cracked it so it is still failry fresh in my mind.)
Using TMON
TMON, unlike Nosy, is a real-time monitor / debugger. We will be using TMON in several situations: to break into active dialog windows, to break into programs that Nosy won't decompile properly, or when Nosy produces such a massive listing that we need to trace the application to see what happens where. To install TMON, just drag the application and the init into the system folder and restart. The application can be launched to configure it, but you probably won't need to do this. If you do configure it, make sure you save the changes in a User Area in the System Folder.
TMON can be entered several ways: System Errors, Debugger traps (this is a great technique for breaking into tough programs), user specified traps, and by pressing the interrupt button on the side of your Mac. If you lack the interrupt button, use the Programmer's Key init - this allows you to hold down command and option and press the startup key on an extended keyboard.
Once in TMON, you are presented with a Menu bar and possibly some windows. A quick note about TMON windows. They can be resized and dragged only in the vertical directions. To change values in the various windows, click the insertion bar in front of the value to change and type right over the old value. Pressing Return chops off the line at the insertion bar, pressing Enter leaves the rest of the line as is. For example, lets say you are changing the address of a dump window. If it currently reads "Dump From 00000000" and you type 1234 over the first 4 values, you have two choices. Hitting Return at this point chops off the last 4 zeroes making the effective address 1234 hex. If you were to hit Enter instead, the remaining zeroes would remain making the effective address 12340000 hex. Here are what the various menu commands do:
Dump / Cmd-d and Asmbly / Cmd-a
Brings up either a dump window or an assembly window. The dump window lists hex and ascii codes for a block of memory and the assembly window disassembles memory. The first line allows you to specify where the window will start its listing: Dump (Assembly) From XXXXXXX where XXXXXXX is an effective address. You can move the insertion bar right into this line and type over whatever is there. You can enter an address directly, specify a register (and the window will start from the address contained in the register), or a register indirect (the window will start from the address in the register, but will remember the register address). Examples: Dump From:
1) 80FFCA Dump listing starts from the absolute address 80FFCA hex. If you scroll the window, the displayed address will change to the address of the first line in the listing.
)2 A5 Dump starts from the address contained in register A5. The address displayed on the Dump From line will be replaced with the address in register A5. If you scroll, the displayed address will again change to reflect the first line in the listing, and if A5 changes, the window will not change.
3) 0(A1) Dump starts from the address in A1 plus zero (in this case). The displayed address on the Dump From line does not change to the address in A1, rather it now displays 00000000(A1) indicating that the listing is anchored to the register. As you scroll, the zeroes will change to reflect how many bytes from the address in A1 the first line in the listing is - also, if A1 changes, the window will automatically change to the new value of A1.
The most common entry for an assembly window is 0(PC) which says to disassemble from the program counter. Then as you step through the program, the window automatically scrolls so that the first line is where the program counter is. The windows list - from left to right - the address, any registers that contain that address (Note the P - for program counter - next to the first line when you disassemble from 0(PC) ), the resource the listing comes from if any (assembly window only), and then either hex and ascii bytes, or disassembled instructions. In addition, the assembly window will display comments to the right, indicating the destination of branches. Additional dump windows can be activated by holding down Shift while clicking on Dump in the menu bar - this is the only display that can have multiple windows. You will find if handy to have, in addition to the dissambly window, a dump window anchored to the A7 register (so make the Dump From read 0(A7) ) so that you can quickly see what addresses are being pushed on the stack. If you need to see what the actual data of these addresses are, just shift-click Dump to bring up successive dump windows, and make each window dump from successive addressess (4 bytes each) on the stack. Remember that the stack moves backwards, so the first thing pushed on the stack will be to the right (in the dump window) of the second thing pushed on the stack, etc.
Brkpts / Cmd-b
Allows the setting of up to eight breakpoints. Simply enter the address of the breakpoint into one of the 8 slots. To remove a breakpoint, type a hyphen for the first digit of the address to remove and hit return. Breakpoints cause TMON to halt execution of the application at the address of the breakpoint. I generally use breakpoints to skip out of long loops. For example, if you are stepping through a section of code and you find a DBRA loop (usually moving a section of data) where the data register has some god-awful value like 63 (often used to move strings), enter a breakpoint at the address of the instruction immediately after the DBRA and then exit. TMON will break execution after the loop has finished.
Regs / Cmd-r
Displays the 16 registers, PC, and status flags, any of which can be modified by typing right over the current values. The flags are displayed as the letter that I have been using - C for Carry, Z for Zero, etc. When the letter is capitalized, the flag is set. To change the value of the flag, simply change the capitalization.
Heap / Cmd-h
Displays memory blocks in the application heap zone. Basically this window lists all allocated blocks of memory in the applications heap zone (in the form of the pointers to the blocks), the size of the block, a digit that is meaningless to me, and the blocks status - either 1) Free, not allocated to anything yet, 2) Nonrel, non-relocatable, 3) Handle at ...., relocatable block with handle at the address specified, or 4) INVALID which means there is a big problem somewhere.
File / Cmd-f
Brings up a window listing all open resource files by file reference number. In most cases, the last number in the list refers to the System File. Entering a file reference number after the Resource file # prompt lists the files resources and where in memory they are. From left to right, the information displayed is: Resource type, Resource ID #, Attributes, location in memory. Attributes are as follows: R = System reference, H = Load into system heap, P = purgeable, L = locked, T = protected, 1 = pre-loaded (loaded at startup time), W = write into resource file. To return to a list of file reference numbers, click the insertion bar before the file number you previously typed in and hit return.
Exit / Cmd-e
Returns control to the Mac. Execution starts from the current value (which can be modified, of course, via the Regs window).
Gosub / Cmd-g
Same as Step (below), except that all JSR and BSR instructions are treated as a single instruction and the subroutine is called invisibly to you. In other words, this command executes exactly as if you had set a breakpoint immediately after the JSR or BSR and then exited. I often use this command the first time through a program to quickly find which JSR calls the subroutine that bombs. If you look at the Font/DA Mover listing above and condsider the Da Mover portion, imagine this as a protected program that Nosy won't handle. You are presented with several subroutines which you certainly don't want to spend valuable time tracing. So, you Gosub each one until you get a bomb. Then you know which one you need to spend time tracing.
Step / Cmd-s
Executes the instruction pointed to by the PC. This command allows you to execute a program one instruction at a time with one limitation (or boon) which is that traps are executed as if they were a single instruction. Use the Trace command to step through the actual ROM trap code. All windows that are affected by the executed instruction are updated automatically.
Trace / Cmd-t
Same as Step, except that ROM traps will be followed into their ROM code. You will never need to do this to crack a program, however if you want to see what a trap is really doing, use this command.
Num / Cmd-n
Brings up TMON's calculator. Any expression (almost) will be evaluated and displayed. For example, entering a trap name will return the trap number; entering a mathematical expression (or a number) will return the result in hex and decimal, etc. There are a million variations on this, non of which I have ever used, so if you have a question, get in touch with me for more info.
User / Cmd-u
This has a wealth of handy commands, but my desctiptions my descriptions will be limited to commands that I have used. There are three different screens associated with the User window: A000 trap functions, Control functions, and Memory functions. To switch pages, click on the line that reads Toggle Pages and press return until you arrive at the page you desire.
Control Functions:
Look for labels: Unknown.
Label table Unknown.
Label add/remove Unknown.
Label file load Unknown.
Registers Unknown. Has something to do with TMON's internal registers.
Leave TMON: queue... Similar to Exit, except that TMON will trap out all events and regain control when you click the mouse. When TMON regains control, the previously generated events will be available in the event queue. To activate this function, click on the Leave TMON... line and press Return.
Leave application... Use this function when your application system bombs. Using 0 as a parameter, attempts to quit to the active shell (usually the Finder), using 1 will attempt to re-launch the program. If you are in a program (not necessarily one you are cracking) and it system bombs, you will dive into the monitor. Use this function with a parameter of 0 and usually the app will quit to the Finder leaving any other open applications running normally.
Shut Down If the above does not gracefully exit to the Finder, you may need to use this function. The higher the number of t